home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / x68000.arc / SOURCE.ARC / LONGNUMB.MOD < prev    next >
Encoding:
Modula Implementation  |  1986-03-05  |  8.9 KB  |  404 lines

  1. IMPLEMENTATION MODULE LongNumbers;            
  2. (* Routines to handle HEX digits for the X68000 cross assembler. *)
  3. (* All but LongPut and LongWrite are limited to 8 digit numbers. *)
  4.  
  5.    FROM FileSystem IMPORT
  6.       File;
  7.  
  8.    IMPORT FileSystem;   (* WriteChar *)
  9.  
  10.    IMPORT Terminal;   (* Write *)
  11.  
  12. (*---
  13. (* These objects are declared in the DEFINITION MODULE *)
  14.  
  15.    CONST
  16.       DIGITS = 8;
  17.       BASE = 16;
  18.  
  19.    TYPE
  20.       LONG = ARRAY [1..DIGITS] OF INTEGER;
  21.                                                     ---*)              
  22.  
  23.    CONST
  24.       Zero = 30H;
  25.       Nine = 39H;
  26.       hexA = 41H;
  27.       hexF = 46H;
  28.  
  29.  
  30.  
  31.    PROCEDURE LongClear (VAR A : LONG);
  32.    (* Sets A to Zero *)
  33.  
  34.       VAR
  35.          i : CARDINAL;
  36.  
  37.       BEGIN
  38.          FOR i := 1 TO DIGITS DO
  39.             A[i] := 0;
  40.          END;
  41.       END LongClear;
  42.  
  43.  
  44.  
  45.    PROCEDURE LongAdd (A, B : LONG; VAR Result : LONG);
  46.    (* Add two LONGs, giving Result *)
  47.  
  48.       VAR
  49.          Carry : INTEGER;
  50.          i : CARDINAL;
  51.  
  52.       BEGIN
  53.          Carry := 0;
  54.          FOR i := 1 TO DIGITS DO
  55.             Result[i] := (A[i] + Carry) + B[i];
  56.             IF Result[i] >= BASE THEN
  57.                Result[i] := Result[i] - BASE;
  58.                Carry := 1;
  59.             ELSE
  60.                Carry := 0;
  61.             END;
  62.          END;
  63.       END LongAdd;
  64.  
  65.  
  66.  
  67.    PROCEDURE LongSub (A, B : LONG; VAR Result : LONG);
  68.    (* Subtract two LONGs (A - B), giving Result *)
  69.  
  70.       VAR
  71.          Borrow : INTEGER;
  72.          i : CARDINAL;
  73.  
  74.       BEGIN
  75.          Borrow := 0;
  76.          FOR i := 1 TO DIGITS DO
  77.             Result[i] := (A[i] - Borrow) - B[i];
  78.             IF Result[i] < 0 THEN
  79.                Result[i] := Result[i] + BASE;
  80.                Borrow := 1;
  81.             ELSE
  82.                Borrow := 0;
  83.             END;
  84.          END;
  85.       END LongSub;
  86.  
  87.  
  88.  
  89.    PROCEDURE CardToLong (n : CARDINAL; VAR A : LONG);
  90.    (* Converts CARDINALs to LONGs *)
  91.  
  92.       VAR
  93.          i : CARDINAL;
  94.  
  95.       BEGIN
  96.          LongClear (A);
  97.  
  98.          i := 1;
  99.          REPEAT
  100.             A[i] := n MOD BASE;
  101.             INC (i);
  102.             n := n DIV BASE;
  103.          UNTIL n = 0;
  104.       END CardToLong;
  105.  
  106.  
  107.  
  108.    PROCEDURE LongToCard (A : LONG; VAR n : CARDINAL) : BOOLEAN;
  109.    (* Converts LONG TO CARDINAL, returns FALSE if conversion impossible *)
  110.       BEGIN
  111.          n := (A[4] * 4096) + (A[3] * 256) + (A[2] * 16) + A[1];
  112.          RETURN ((A[5] = 0) AND (A[6] = 0) AND (A[7] = 0) AND (A[8] = 0));
  113.       END LongToCard;
  114.  
  115.  
  116.  
  117.    PROCEDURE LongToInt (A : LONG; VAR n : INTEGER) : BOOLEAN;
  118.    (* Converts LONG to INTEGER, returns FALSE if conversion impossible *)
  119.  
  120.       VAR
  121.          TempC : CARDINAL;
  122.          Neg : BOOLEAN;
  123.  
  124.       BEGIN
  125.          IF (A[5] = 0) AND (A[6] = 0) AND (A[7] = 0) AND (A[8] = 0) THEN
  126.             Neg := FALSE;
  127.          ELSIF (A[5] = 15) AND (A[6] = 15) AND (A[7] = 15) AND (A[8] = 15) THEN
  128.             Neg := TRUE;
  129.          ELSE
  130.             RETURN FALSE;   (* Out of INTEGER range *)
  131.          END;
  132.       
  133.          TempC := (A[4] * 4096) + (A[3] * 256) + (A[2] * 16) + A[1];
  134.          IF ((TempC <= 32767) AND (NOT Neg)) OR ((TempC > 32767) AND Neg) THEN
  135.             n := INTEGER (TempC);
  136.             RETURN TRUE;
  137.          ELSE
  138.             RETURN FALSE;
  139.          END;
  140.       END LongToInt;
  141.  
  142.  
  143.  
  144.    PROCEDURE LongInc (VAR A : LONG; n : CARDINAL);
  145.    (* Increment LONG by n *)
  146.  
  147.       VAR
  148.          T : LONG;
  149.  
  150.       BEGIN
  151.          CardToLong (n, T);
  152.          LongAdd (A, T, A);
  153.       END LongInc;
  154.  
  155.  
  156.  
  157.    PROCEDURE LongDec (VAR A : LONG; n : CARDINAL);
  158.    (* Decrement LONG by n *)
  159.  
  160.       VAR
  161.          T : LONG;
  162.  
  163.       BEGIN
  164.          CardToLong (n, T);
  165.          LongSub (A, T, A);
  166.       END LongDec;
  167.  
  168.  
  169.  
  170.    PROCEDURE LongCompare (A, B : LONG) : INTEGER;
  171.    (* Returns: 0 if A = B, -1 if A < B, +1 if A > B *)
  172.  
  173.       VAR
  174.          i : CARDINAL;
  175.  
  176.       BEGIN
  177.          i := DIGITS;
  178.          WHILE (i > 0) AND (A[i] = B[i]) DO
  179.             DEC (i);
  180.          END;
  181.          
  182.          IF i = 0 THEN
  183.             RETURN 0;
  184.          ELSIF A[i] < B[i] THEN
  185.             RETURN -1;
  186.          ELSIF A[i] > B[i] THEN
  187.             RETURN +1;
  188.          ELSE
  189.             (* Impossible! *)
  190.          END;
  191.       END LongCompare;
  192.  
  193.  
  194.  
  195.    PROCEDURE GetDigit (n : INTEGER) : CHAR;
  196.    (* Function returning HEX character corresponding to digit *) 
  197.  
  198.       BEGIN
  199.          IF (n >= 0) AND (n <= 9) THEN
  200.             RETURN CHR (CARDINAL (n) + Zero);
  201.          ELSIF (n >= 10) AND (n <= 15) THEN
  202.             RETURN CHR ((CARDINAL (n) - 10) + hexA);
  203.          ELSE
  204.             RETURN '*';
  205.          END;
  206.       END GetDigit;
  207.  
  208.  
  209.  
  210.    PROCEDURE LongPut (VAR f : File; A : ARRAY OF INTEGER; Size : CARDINAL);
  211.    (* Put LONG number in FILE f *)
  212.    
  213.       VAR
  214.          i : CARDINAL;
  215.    
  216.       BEGIN
  217.          IF Size = 0 THEN
  218.             RETURN;
  219.          END;
  220.  
  221.          DEC (Size);   (* adjust for zero-based array *)
  222.          IF Size > HIGH (A) THEN
  223.             Size := HIGH (A);
  224.          END;
  225.  
  226.          FOR i := Size TO 0 BY -1 DO
  227.             FileSystem.WriteChar (f, GetDigit (A[i]));
  228.          END;
  229.       END LongPut;
  230.  
  231.  
  232.  
  233.    PROCEDURE LongWrite (A : ARRAY OF INTEGER; Size : CARDINAL);
  234.    (* Write LONG number to console screen *)
  235.  
  236.       VAR
  237.          i : CARDINAL;
  238.    
  239.       BEGIN
  240.          IF Size = 0 THEN
  241.             RETURN;
  242.          END;
  243.  
  244.          DEC (Size);
  245.          IF Size > HIGH (A) THEN
  246.             Size := HIGH (A);
  247.          END;
  248.  
  249.          FOR i := Size TO 0 BY -1 DO
  250.             Terminal.Write (GetDigit (A[i]));
  251.          END;
  252.       END LongWrite;
  253.  
  254.  
  255.  
  256.    PROCEDURE IsHEX (c : CHAR) : BOOLEAN;
  257.    (* checks if c is one of 0..9, A..F *)
  258.    
  259.       VAR
  260.          C : CARDINAL;
  261.  
  262.       BEGIN
  263.          C := ORD (CAP (c));
  264.       
  265.          RETURN (((C >= Zero) AND (C <= Nine)) OR
  266.                  ((C >= hexA) AND (C <= hexF)));
  267.       END IsHEX;
  268.  
  269.  
  270.    
  271.    PROCEDURE GetHEX (c : CHAR) : INTEGER;
  272.    (* returns HEX value of character *)
  273.  
  274.       VAR
  275.          C : CARDINAL;
  276.  
  277.       BEGIN
  278.          C := ORD (CAP (c));
  279.          IF C < hexA THEN
  280.             RETURN INTEGER (C - Zero);
  281.          ELSE
  282.             RETURN 10 + INTEGER (C - hexA);
  283.          END;
  284.       END GetHEX;
  285.  
  286.  
  287.  
  288.    PROCEDURE StringToLong (S : ARRAY OF CHAR; VAR A : LONG) : BOOLEAN;
  289.    (* Converts a string (in HEX) into a LONG *)
  290.  
  291.       VAR
  292.          i, j : CARDINAL;
  293.  
  294.       BEGIN
  295.          LongClear (A);
  296.  
  297.          IF S[0] # '$' THEN
  298.             RETURN FALSE;   (* not a HEX string *)
  299.          ELSE
  300.             j := 1;
  301.             WHILE (IsHEX (S[j])) AND (j <= DIGITS) DO
  302.                INC (j);
  303.             END;     
  304.  
  305.             DEC (j);   (* gone too far, so back up one *)
  306.             i := 1;
  307.             WHILE j > 0 DO
  308.                A[i] := GetHEX (S[j]);
  309.                INC (i);   DEC (j);
  310.             END;       
  311.  
  312.             IF A[i - 1] > 7 THEN   (* sign extend *)
  313.                FOR j := i TO DIGITS DO
  314.                   A[j] := 15;
  315.                END;
  316.             END;
  317.             RETURN (i > 1);
  318.          END;
  319.       END StringToLong;
  320.  
  321.  
  322.  
  323.    PROCEDURE BinStrToLong (S : ARRAY OF CHAR; VAR A : LONG) : BOOLEAN;
  324.    (* Converts a string (in Binary, maximum of 16 digits) into a LONG *)
  325.  
  326.       CONST
  327.          MAXBit = 16;
  328.  
  329.       VAR
  330.          Bin, i : CARDINAL;
  331.          Neg : BOOLEAN;
  332.  
  333.       BEGIN
  334.          IF S[0] # '%' THEN
  335.             RETURN FALSE;
  336.          END;
  337.  
  338.          IF S[1] = '1' THEN
  339.             Neg := TRUE;
  340.          ELSE
  341.             Neg := FALSE;
  342.          END;
  343.  
  344.          Bin := 0;
  345.          i := 1;
  346.          WHILE S[i] # 0C DO
  347.             IF i > MAXBit THEN
  348.                RETURN FALSE;
  349.             END;
  350.             Bin := Bin * 2;
  351.             IF S[i] = '0' THEN
  352.                (* No Action Needed *)
  353.             ELSIF S[i] = '1' THEN
  354.                Bin := Bin + 1;
  355.             ELSE   (* Not a valid binary digit *)
  356.                RETURN FALSE;
  357.             END;
  358.             INC (i);
  359.          END;
  360.  
  361.          CardToLong (Bin, A);
  362.  
  363.          IF Neg THEN   (* sign extend *)
  364.             i := DIGITS;
  365.             WHILE A[i] = 0 DO
  366.                A[i] := 15;
  367.                DEC (i);
  368.             END;
  369.             IF A[i] < 8 THEN
  370.                IF A[i] < 4 THEN
  371.                   IF A[i] < 2 THEN
  372.                      A[i] := A[i] + 2;
  373.                   END;
  374.                   A[i] := A[i] + 4;
  375.                END;
  376.                A[i] := A[i] + 8;
  377.             END;
  378.          END;
  379.  
  380.          RETURN TRUE;
  381.       END BinStrToLong;
  382.  
  383.  
  384.  
  385.    PROCEDURE AddrBoundL (VAR A : LONG);
  386.    (* Forces A to a long word boundary *)
  387.       BEGIN
  388.          WHILE NOT (CARDINAL (A[1]) IN {0, 4, 8, 12}) DO
  389.             LongInc (A, 1);
  390.          END;
  391.       END AddrBoundL;
  392.  
  393.  
  394.  
  395.    PROCEDURE AddrBoundW (VAR A : LONG);
  396.    (* Forces A to a word boundary *)
  397.       BEGIN
  398.          WHILE NOT (CARDINAL (A[1]) IN {0, 2, 4, 6, 8, 10, 12, 14}) DO
  399.             LongInc (A, 1);
  400.          END;
  401.       END AddrBoundW;
  402.  
  403. END LongNumbers.
  404.